REMEZ |
REMEZ is a library that allows designing: Low Pass, Band Pass, High Pass, Hilbert and Differentiator filters. The REMEZ library is based on the Parks-McClellan algorithm, see Discrete-Time Signal Processing (Alan V. Oppenheim and Ronal W. Schafer). REMEZ es una librería que permite diseñar filtros: Pasa Baja, Pasa Banda, Pasa Alta, de Hilbert y Diferenciadores. La librería de REMEZ está basa en el algoritmo de Parks-McClellan, vea Discrete-Time Signal Processing (Alan V. Oppenheim and Ronal W. Schafer). |
Problem 1 |
Create a project called RemezTest to create a Low Pass filter using the REMEZ algorithm. The program must display the Impulse and Frequency Response. Use a slider to control the length of the filter. The filter has a cut frequency of 2.1 radians. Additionally, the filter must eliminate any frequency greater than 2.6 radians. Cree un proyecto llamado RemezTest para crear un filtro pasa bajas usando el algoritmo de REMEZ. El progrma debe mostrar la respuesta al impulso y la respuesta en frecuencia. Use un slider para la longitud del filtro. El filtro tiene una frecuencia de corte de 2.1 radianes. Adicionalmente, el filtro debe eliminar cualquier frecuencia mayor a 2.6 radianes. |
Solution A |
Create a Wintempla Dialog Application. Using Wintempla create the GUI shown below. After inserting the slider for the length of the filter, double click the control and mark the HSCROLL event. Cree una aplicación de Diálogo de Wintempla. Use Wintempla para la crear la GUI mostrada debajo. Después de insertar el slider para la longitud del filtro, haga doble clic en el control para marcar el evento de HSCROLL. |
Solution B |
Edit the RemezTest.h file as shown. Edite el archivo RemezTest.h como se muestra. |
RemezTest.h |
#pragma once //______________________________________ RemezTest.h #include "resource.h" class RemezTest: public Win::Dialog { public: RemezTest() { } ~RemezTest() { } void UpdateGraphs(); protected: ... }; |
Solution C |
Edit the RemezTest.cpp file as shown. Edite el archivo RemezTest.cpp como se muestra. |
RemezTest.Cpp |
... void RemezTest::Window_Open(Win::Event& e) { //________________________________________________________ sldLength sldLength.SetRange(2, 200); sldLength.Position = 10; tbxLength.IntValue = 10; //________________________________________________________ xyFreqResp xyFreqResp.CaptionX = L"Frequency"; xyFreqResp.CaptionY = L"Amplitude"; xyFreqResp.MinX= 0.0; xyFreqResp.MaxX= M_PI; xyFreqResp.MinY= 0.0; xyFreqResp.MaxY= 1.2; xyFreqResp.DivisionCountY = 6; xyFreqResp.Graphs.Add(); //________________________________________________________ xyImpulseResponse xyImpulseResponse.CaptionX = L"n"; xyImpulseResponse.CaptionY = L"h[n]"; xyImpulseResponse.MinX= -1.0; xyImpulseResponse.MaxX= 6.28; xyImpulseResponse.MinY= -0.2; xyImpulseResponse.MaxY= 0.8; xyImpulseResponse.DivisionCountY = 5; xyImpulseResponse.Graphs.Add(); xyImpulseResponse.Graphs[0].Type = Win::Graph::impulse; //________________________________________________________ xyError //xyError.CaptionX = L"Frequency"; //xyError.CaptionY = L"Error"; //xyError.MinX= 0.0; //xyError.MaxX= M_PI; //xyError.MinY= -0.2; //xyError.MaxY= 0.2; //xyError.Graphs.Add(); // UpdateGraphs(); } void RemezTest::UpdateGraphs() { Win::HourGlassCursor hgc(true); const int filterLength = tbxLength.IntValue; vector<Math::Remez::Band> bands; Math::Remez::Band band; valarray<double> h; valarray<double> freq; valarray<double> errorData; //_________________________________________________________ Low Pass band.w1 = 0.0; band.w2 = 2.1; //M_PI/100.0; band.priory = 1.0; band.gain = 1.0; bands.push_back(band); // band.w1 = 2.6;//2.0*M_PI/100.0; band.w2 = M_PI; band.priory = 1.0; band.gain = 0.0; bands.push_back(band); //// //double error = Math::Remez::ImpulseResponse(bands, filterLength, REMEZ_BANDPASS, h, errorData, freq);//This line is for debug double error = Math::Remez::ComputeImpulseResponse(bands, filterLength, h); //Low Pass //_________________________________________________________ Hilbert //band.w1 = 0.1*M_PI; //band.w2 = M_PI; //band.priory = 1.0; //band.gain = 1.0; //bands.push_back(band); //double error = Math::Remez::ImpulseResponse(bands, filterLength, REMEZ_HILBERT, h, errorData, freq);//This line is for debug //double error = Math::Remez::ComputeHilbertImpulseResponse(filterLength, h); //________________________________________________________ xyImpulseResponse const int len = h.size(); int i; xyImpulseResponse.Graphs[0].SetPointCount(len); for(i=0; i<len; i++) { xyImpulseResponse.Graphs[0][i].x = i; xyImpulseResponse.Graphs[0][i].y = h[i]; } xyImpulseResponse.MaxX= len; xyImpulseResponse.RefreshAll(); //________________________________________________________ xyFreqResp //xyFreqResp.Graphs[0].SetPointCount(len); //for(i=0; i<len; i++) //{ // xyFreqResp.Graphs[0][i].x = i;//freq[i]; // xyFreqResp.Graphs[0][i].y = h[i]; //} // valarray<complex<double> > H; Math::Dsp::FourierTransformRe(h, H); xyFreqResp.Graphs[0].SetPointCount(H.size()); for(i=0; i<(int)h.size(); i++) { xyFreqResp.Graphs[0][i].x = i; xyFreqResp.Graphs[0][i].y = abs(H[i]); } xyFreqResp.MaxX = h.size(); xyFreqResp.RefreshAll(); //________________________________________________________ xyError //const int errorLen = errorData.size(); //xyError.Graphs[0].SetPointCount(errorLen); //for(i=0; i<errorLen; i++) //{ // xyError.Graphs[0][i].x = freq[i]; // xyError.Graphs[0][i].y = errorData[i]; //} //xyError.Graphs[0].Type = Win::Graph::cross; //xyError.DivisionCountY = 5; //xyError.RefreshAll(); // //wchar_t text[256]; //_snwprintf_s(text, 256, _TRUNCATE, L"Error = %g", error); //this->Text = text; } void RemezTest::sldLength_Hscroll(Win::Event& e) { tbxLength.IntValue = sldLength.Position; UpdateGraphs(); } |
Kaiser Window |
The Kaiser Window can be used to design digital Filters. It has two parameters, the length of the filter and beta. La ventana de Kaiser puede ser usada para diseñar Filtros digitales. Este tiene dos parámetros, la longitud del filtro y la beta. |
Problem 2 |
Repeat the previous problem using the Kaiser Window method, your project must be called KaiserTest. Repita el problema anterior usando el método de la ventana de Kaiser, su proyecto debe ser llamado KaiserTest. |
Solution A |
Create a Wintempla Dialog Application. Using Wintempla create the GUI shown below. After inserting the slider for the length of the filter, double click the control and mark the HSCROLL event. Insert another slider for beta. Cree una aplicación de diálogo de Wintempla. Usando Wintempla cree la GUI mostrada debajo. Después de insertar el slider para longitud del filtro, haga clic doble en el control y marque el evento de HSCROLL. Inserte otro slider para beta. |
Solution B |
Edit the KaiserTest.h file as shown. Edite el archivo KaiserTest.h como se muestra. |
KaiserTest.h |
#pragma once //______________________________________ KaiserTest.h #include "resource.h" class KaiserTest: public Win::Dialog { public: KaiserTest() { } ~KaiserTest() { } void UpdateGraphs(); protected: ... }; |
Solution C |
Edit the KaiserTest.cpp file as shown. Edite el archivo KaiserTest.cpp como se muestra. |
KaiserTest.Cpp |
... void KaiserTest::Window_Open(Win::Event& e) { //________________________________________________________ sldLength sldLength.SetRange(2, 200); sldLength.Position = 10; tbxLength.IntValue = 10; //________________________________________________________ sldBeta sldBeta.SetRange(1, 3000); sldBeta.Position = 100; tbxBeta.DoubleValue = 1.0; //________________________________________________________ xyFreqResp xyFreqResp.CaptionX = L"Frequency"; xyFreqResp.CaptionY = L"Amplitude"; xyFreqResp.MinX= 0.0; xyFreqResp.MaxX= M_PI; xyFreqResp.MinY= 0.0; xyFreqResp.MaxY= 1.2; xyFreqResp.DivisionCountY = 6; xyFreqResp.Graphs.Add(); //________________________________________________________ xyImpulseResponse xyImpulseResponse.CaptionX = L"n"; xyImpulseResponse.CaptionY = L"h[n]"; xyImpulseResponse.MinX= -1.0; xyImpulseResponse.MaxX= 6.28; xyImpulseResponse.MinY= -0.2; xyImpulseResponse.MaxY= 0.8; xyImpulseResponse.DivisionCountY = 5; xyImpulseResponse.Graphs.Add(); xyImpulseResponse.Graphs[0].Type = Win::Graph::impulse; // UpdateGraphs(); } void KaiserTest::sldLength_Hscroll(Win::Event& e) { tbxLength.IntValue = sldLength.Position; UpdateGraphs(); } void KaiserTest::sldBeta_Hscroll(Win::Event& e) { tbxBeta.DoubleValue = sldBeta.Position/100.0; UpdateGraphs(); } void KaiserTest::UpdateGraphs() { Win::HourGlassCursor hgc(true); const int filterLength = tbxLength.IntValue; const double beta = tbxBeta.DoubleValue; // valarray<double> h; Math::Dsp::ImpulRespLowPass(beta, filterLength, 2.1, h); //________________________________________________________ xyImpulseResponse const int len = h.size(); int i; xyImpulseResponse.Graphs[0].SetPointCount(len); for(i=0; i<len; i++) { xyImpulseResponse.Graphs[0][i].x = i; xyImpulseResponse.Graphs[0][i].y = h[i]; } xyImpulseResponse.MaxX= len; xyImpulseResponse.RefreshAll(); //________________________________________________________ xyFreqResp valarray<complex<double> > H; Math::Dsp::FourierTransformRe(h, H); xyFreqResp.Graphs[0].SetPointCount(H.size()); for(i=0; i<(int)h.size(); i++) { xyFreqResp.Graphs[0][i].x = i; xyFreqResp.Graphs[0][i].y = abs(H[i]); } xyFreqResp.MaxX = h.size(); xyFreqResp.RefreshAll(); } |
Problem 3 |
Create a Wintempla dialog application called LowPass to filter (in real time) a music wave file. After creating the project open the stdafx.h file and remove the comments from the line #define WIN_DAC_ADC_SUPPORT. Cree una aplicación de diálogo de Wintempla llamada LowPass para filtrar (en tiempo real) un archivo de música wave. Después de crear el proyecto abra el archivo stdafx.h y remueva los comentarios de la línea #define WIN_DAC_ADC_SUPPORT. |
Solution A |
Open Wintempla to edit the GUI. Using theShow All Controls in Toolbox from the toolbar insert a DAC control as shown below (on the events tabs, be sure all events are unselected). Insert two labels, two textboxes, two slides (with the Hscroll event), a button, a XyChart and drop down list. Abra Wintempla y edite la GUI. Usando theShow All Controls in Toolbox desde la barra de herramientas inserta un control DAC como se muestra debajo (en la pestaña de eventos, asegúrate de que todos los eventos estén deseleccionado). Inserta dos etiquetas, dos cajas de texto, dos sliders (con el evento HScroll), un botón, una XyChart y una lista desplegable. |
Solution B |
Edit the LowPass.h file and the LowPass.cpp file to implement the three functions of the Mm::IAudioOut interface (Observe the the LowPass class is derived from Mm::IAudioOut). Remember that an interface is used to pass a set of functions to another function or another object. Edite los archivos LowPass.h y LowPass.cpp para implementar las tres funciones de la interface Mm::IAudioOut (Observa que la clase LowPass se deriva de Mm::IAudioOut). Recuerde que una interface es usada para pasar un conjunto de funciones a otra función u objeto. |
LowPass.h |
#pragma once //______________________________________ LowPass.h #include "resource.h" class LowPass: public Win::Dialog, public Mm::IDataTransfer { public: LowPass() { } ~LowPass() { } Math::FIRFilter16 fir; Mm::WaveFile waveFile; void UpdateFilter(); //______________________________________________________________ Mm::IDataTransfer void OnDataStarted(unsigned int samplesPerSec, unsigned int numbChannels, unsigned int bitsResolution); void OnData(WAVEHDR* waveHdr); void OnDataStopped(); protected: ... }; |
LowPass.cpp |
... void LowPass::Window_Open(Win::Event& e) { //________________________________________________________ sldFc sldFc.SetRange(1, 20000); sldFc.Position = 1000; tbxFc.IntValue = 1000; //________________________________________________________ sldBeta sldBeta.SetRange(1, 3000); sldBeta.Position = 200; tbxBeta.DoubleValue = 2.0; //________________________________________________________ xyFR xyFR.CaptionX = L"Frequency (Hz)"; xyFR.CaptionY = L"H[f]"; xyFR.MinX= 0.0; xyFR.MaxX= 22050; xyFR.MinY= 0.0; xyFR.MaxY= 1.2; xyFR.DivisionCountY = 6; xyFR.Graphs.Add(); xyFR.RefreshAll(); // UpdateFilter(); // this->btPlay.Enabled = true; this->btStop.Enabled = false; } void LowPass::sldFc_Hscroll(Win::Event& e) { tbxFc.IntValue = sldFc.Position; UpdateFilter(); } void LowPass::sldBeta_Hscroll(Win::Event& e) { tbxBeta.DoubleValue = sldBeta.Position/100.0; UpdateFilter(); } void LowPass::UpdateFilter() { const int length = 200; const double wc = M_PI*tbxFc.IntValue/22050.0; const double beta = tbxBeta.DoubleValue; // valarray<double> impulseResponse; Math::Dsp::ImpulRespLowPass(beta, length, wc, impulseResponse); fir.Create(impulseResponse); // valarray<complex <double> > H; Math::Dsp::FourierTransformRe(impulseResponse, H); this->xyFR.Graphs[0].SetPointCount(length/2); for(int i = 0; i < length/2; i++) { this->xyFR.Graphs[0][i].x = 2.0*i*22050.0/length; this->xyFR.Graphs[0][i].y = abs(H[i]); } xyFR.RefreshAll(); } void LowPass::btStop_Click(Win::Event& e) { dacOutput.Stop(); } void LowPass::btPlay_Click(Win::Event& e) { //________________________________________________________ Open the Wave File const wchar_t* error = waveFile.OpenForReading(L"C:\\AudioLab\\music\\Cecilia\\El caso es andar.wav"); if (error != NULL) { this->MessageBox(error, L"FilePlayer", MB_OK | MB_ICONERROR); return; } dacOutput.Start(44100, 2, 16, 16384, this); } void LowPass::OnDataStarted(unsigned int samplesPerSec, unsigned int numbChannels, unsigned int bitsResolution) { btPlay.Enabled = false; btStop.Enabled = true; EnableCloseButton(false); } void LowPass::OnData(WAVEHDR* waveHdr) { waveHdr->dwBytesRecorded = waveFile.ReadData(waveHdr->lpData, waveHdr->dwBufferLength); Sys::Sample16 *samples = (Sys::Sample16 *)waveHdr->lpData; const int numSamples = waveHdr->dwBytesRecorded/4; for (int i = 0; i < numSamples; i++) { samples[i].channel_1 = fir.GenerateOutputSymmetric(samples[i].channel_1); samples[i].channel_2 = samples[i].channel_1; } } void LowPass::OnDataStopped() { btPlay.Enabled = true; btStop.Enabled = false; waveFile.Close(); EnableCloseButton(true); } |
Solution C |
Run the program and click the Play button. Select a wave file with two channels, 44100 Hz and 16 bits. Ejecute el programa y haga clic en el botón de Play. Seleccione un archivo Wave con dos canales, 44100 Hz y 16 bits. |